feat: implement clusterrole primitive#37
Merged
sourcehawk merged 28 commits intomainfrom Mar 25, 2026
Merged
Conversation
There was a problem hiding this comment.
Pull request overview
Adds a new clusterrole primitive to the operator-component-framework so controllers can manage Kubernetes rbac.authorization.k8s.io/v1 ClusterRole objects using the same builder/mutator/flavor patterns as existing primitives.
Changes:
- Introduces
pkg/primitives/clusterrolewithResource,Builder,Mutator, and field-application flavors for ClusterRole-specific behavior. - Adds a new shared mutation editor
PolicyRulesEditorunderpkg/mutation/editorsto support typed.rulesmutation. - Adds an end-to-end example (
examples/clusterrole-primitive) and full primitive documentation (docs/primitives/clusterrole.md).
Reviewed changes
Copilot reviewed 15 out of 15 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| pkg/primitives/clusterrole/resource.go | Defines the ClusterRole Resource wrapper and default field applicator. |
| pkg/primitives/clusterrole/mutator.go | Implements plan-and-apply mutator for metadata, rules, and aggregationRule. |
| pkg/primitives/clusterrole/builder.go | Provides fluent builder API and validation/workarounds for cluster-scoped objects. |
| pkg/primitives/clusterrole/flavors.go | Adds flavors to preserve labels/annotations and externally-added rules. |
| pkg/primitives/clusterrole/*_test.go | Adds unit tests for builder, mutator, and flavors. |
| pkg/mutation/editors/policyrules.go | Adds a reusable PolicyRulesEditor for Role/ClusterRole rules mutation. |
| pkg/mutation/editors/policyrules_test.go | Adds tests for PolicyRulesEditor. |
| examples/clusterrole-primitive/* | Adds a runnable example demonstrating mutation composition and reconciliation. |
| docs/primitives/clusterrole.md | Adds user-facing documentation for the new primitive API and usage patterns. |
Owner
Author
Claude Review Cycle 1 CompleteAddressed:
Intentionally ignored: <!-- claude-review-cycle --> |
Owner
Author
|
approved but wait until last |
102978d to
a1d3fca
Compare
Owner
Author
Claude Review Cycle 1 CompleteAddressed:
Intentionally ignored:
<!-- claude-review-cycle --> |
Owner
Author
Claude Review Cycle 1 CompleteAddressed:
Intentionally ignored: <!-- claude-review-cycle --> |
Owner
Author
Claude Review Cycle 1 CompleteAddressed:
Intentionally ignored: <!-- claude-review-cycle --> |
84f470c to
4b6eaa0
Compare
Owner
Author
Claude Review Cycle 1 CompleteAddressed:
Intentionally ignored: <!-- claude-review-cycle --> |
Introduces a typed editor for mutating the .rules field of Role and ClusterRole resources, following the same pattern as existing editors (ConfigMapDataEditor, ObjectMetaEditor). Provides AddRule, RemoveRuleByIndex, Clear, and Raw escape hatch operations. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Implements the ClusterRole primitive as a Static, cluster-scoped resource. Includes builder (with name-only validation, no namespace required), resource, mutator (EditObjectMetadata, EditRules, AddRule, SetAggregationRule), and flavors (PreserveCurrentLabels, PreserveCurrentAnnotations, PreserveExternalRules). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Documents the ClusterRole primitive API, mutation system, editors, flavors, aggregation rule support, and usage patterns. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Demonstrates feature-gated RBAC rule composition using the clusterrole primitive, including core rules, version labels, and conditional secret/deployment access mutations. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Remove feature-plan abstraction from Mutator: the FeatureMutator interface in internal/generic uses an unexported beginFeature() method, so the clusterrole Mutator could never satisfy it across package boundaries. Replaced with flat intent lists and fixed category ordering (metadata → rules → aggregation), which matches the actual runtime behavior. - Update mutator test: replace TestMutator_MultipleFeatures (which called unexported beginFeature() directly) with TestMutator_MultipleMutations that exercises the public API only. - Update docs to reflect that namespace must be empty (not just optional) for cluster-scoped resources, matching ValidateBase() behavior. - Update mutation ordering docs to accurately describe flat category ordering rather than per-feature boundaries. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Defensively allocate a local zero-value slice when a nil pointer is passed, matching the pattern used by NewConfigMapDataEditor. This prevents nil-pointer panics in Raw()/AddRule()/RemoveRuleByIndex()/Clear(). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…itation - Remove redundant "valid clusterrole without namespace" test case that was identical to "valid clusterrole" - Document cluster-scoped ownership limitation in clusterrole docs - Add comment in example about namespaced owner limitation with real clusters Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ExternalRules - Adopt per-feature planning pattern (beginFeature/featurePlan) in the ClusterRole mutator for consistency with ConfigMap and Deployment primitives, ensuring mutation ordering matches registration order - Update ownership limitation docs to reflect actual framework behavior: scope mismatch is detected and owner ref is skipped with a log message, rather than rejecting the reconcile - Remove PreserveExternalRules from example and docs feature-gating walkthrough to avoid conflict where disabled feature-gated rules would be preserved from the live object - Add documentation note about PreserveExternalRules trade-off with feature-gated mutations - Remove duplicate cluster-scoped validation tests in builder_static_test Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…pplicator Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Initialize plans slice and active pointer directly in the constructor to avoid creating an empty feature when mutate_helper.go calls beginFeature() on the first feature. Mirrors the fix applied to deployment and configmap mutators in #42. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Use set-based (order-independent) comparison for PolicyRule slices in PreserveExternalRules to avoid duplicating rules after webhook normalization - DeepCopy AggregationRule in SetAggregationRule to prevent caller mutations from affecting recorded intent - Remove duplicate nil/name validation in Build(), delegating to generic.StaticBuilder.ValidateBase() consistent with ConfigMap primitive - Add tests for reordered-but-equivalent rules and aggregation rule immutability Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
After rebasing on main, the clusterrole mutator still had the unexported beginFeature() method. Rename to BeginFeature() to align with the exported FeatureMutator interface in internal/generic/resource_workload.go. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Update comments and documentation for PreserveExternalRules to accurately describe that slice fields are compared as unordered sets. Fix GoDoc capitalization of ClusterRole in Mutation type comment. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Delegate state and With* calls directly to the generic builder instead of storing mutations/flavors/extractors locally and replaying them in Build(). This matches the pattern used by other primitives (configmap, deployment) and avoids duplicated plumbing that could drift. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ate docs - CoreRulesMutation and VersionLabelMutation now use nil Feature (truly unconditional) instead of a no-op NewResourceFeature(version, nil) - Add ClusterRole to the Built-in Primitives table in primitives.md - Add PolicyRulesEditor to the Mutation Editors table in primitives.md - Mention PolicyRulesEditor in clusterrole.md capabilities table Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…false ordering claims in tests - Update docs/primitives.md to reflect that PolicyRulesEditor applies to both Role and ClusterRole, not just ClusterRole - Rename and re-scope two tests that falsely claimed to verify operation ordering when the assertions were order-independent Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ource-level tests - TestBuilder_WithMutation now uses a Mutation with a non-nil Mutate func so the test models valid usage instead of an impossible configuration. - Add comprehensive resource-level tests for ClusterRole: Identity(), Object() deep-copy, Mutate with default and custom field applicators, mutation execution, feature ordering, and data extraction. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ot set semantics The docs claimed slice fields were compared as "unordered sets" but the implementation treats duplicates as significant (multiset equality). Updated comments to accurately describe the behavior rather than changing the comparison logic. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Align with configmap and deployment mutators — NewMutator no longer creates an initial feature plan. BeginFeature must be called before registering any mutations. Updates all tests accordingly and adds constructor/plan invariant tests. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…tive Align with the framework's move to Server-Side Apply. Remove DefaultFieldApplicator, WithCustomFieldApplicator, WithFieldApplicationFlavor, the flavors.go file, and all associated tests. Update builder to use the new generic constructor signature (without defaultApplicator). Update Mutate tests to use Object() output instead of empty structs. Strip field applicator and flavor sections from primitive docs. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Document why clusterrole-primitive example is excluded from make run-examples - Use slices.Delete in PolicyRulesEditor.RemoveRuleByIndex to avoid memory retention Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
… discarding edits Passing a nil *[]PolicyRule pointer to NewPolicyRulesEditor is a programmer error — edits would be recorded against a local variable and never propagate back to the Kubernetes object. Fail fast with a clear panic message instead of silently swallowing the mistake. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Mutator methods that access m.active (EditObjectMetadata, EditRules, SetAggregationRule) now call requireActive() which panics with a clear message instead of an opaque nil-pointer dereference. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Implements the
clusterroleKubernetes resource primitive following the pattern established by the existingConfigMapandDeploymentprimitives.Summary
clusterroleprimitive package underpkg/primitives/clusterrole/PolicyRulesEditortopkg/mutation/editors/(reusable for Role and ClusterRole)internal/generic/builder_base.goChecklist
internal/generic/builder_base.go) and a newPolicyRulesEditor(pkg/mutation/editors/)